<?php

namespace coreapi\extensions\db;

use yii;
use yii\base\Model;


/**
 * 工具类
 * @author martinzhang
 */
class ZTools extends Model{
	
	/**
	 * 调试、打印变量
	 * @param mixed $res
	 */
	public static function p($res){
		if(is_string($res)){
			echo $res.'<br />';
		}elseif(is_array($res)){
			echo '<pre>';
			print_r($res);
			echo '</pre>';
		}else{
			echo '<pre>';
			var_dump($res);
			echo '</pre>';
		}
	}
	
	/**
	 * 获取指定长度的随机字符串(纯数字)
	 * @param int $length  获取长度
	 * @return string
	 */
	public static function generate_randnum($length) {
		$chars = '1234567890';
		$randstr = '';
		for ( $i = 0; $i < $length; $i++ ){

			$randstr .= $chars[ mt_rand(0, strlen($chars) - 1) ];
		}
		return $randstr;
	}
	
	/**
	 * 获取指定长度的随机字符串(数字+字母混合)
	 * @param int $length  获取长度
	 * @return string
	 */
	public static function generate_randstr($length) {
		$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
		$randstr = '';
		for ( $i = 0; $i < $length; $i++ ){
			$randstr .= $chars[ mt_rand(0, strlen($chars) - 1) ];
		}
		return $randstr;
	}
	
	/**
	 * 生成各种带前导0的订单编号(形如:00001 00022)
	 * @param int $num    编号值
	 * @param int $strlen 生成的编号部长度
	 * @return string     返回生成的带前导0的编号
	 * @author martinzhang
	 */
	public static function createBianHao($num, $strlen=5){
		return sprintf("%'0{$strlen}s", $num);
	}
	
	/**
	 * 将字符或数组过滤掉空值，并去重格式化为数组
	 * @param array|stirng $var  必选  待格式化的字符串或数组
	 * @param string $delimiter  可选  如果$var是字符串,指定使用哪种分隔符分隔(默认按逗号分隔)
	 * @uses                     示例  $var='1,2,,3,3,,,4,,'; ---> [1,2,3,4]
	 * @return array             返回格式化后的数组
	 * @author martinzhang
	 */
	public static function fmtArrayFilter($var, $delimiter=','){
		if(is_string($var) || is_numeric($var)){
			return array_unique(array_filter(explode($delimiter, $var)));
		}elseif(is_array($var)){
			return array_unique(array_filter($var));
		}else{
			return [];
		}
	}
	
	/**
	 * 将数组过滤掉空值(不过滤0)
	 * @param  array $arr  必选 待过滤的数组
	 * @return array           过滤好的数组
	 * @author martinzhang
	 */
	public static function arrayFilterNull($arr){	
		foreach($arr as $k=>$v){
			if($v==''){
				unset($arr[$k]);	//删除
			}
		}	
		return $arr;
	}
	
	
	/**
	 * 将字符或数组过滤掉空值去重后，再将元素值转换为字符类型OR整型
	 * @param  array|stirng $var      待格式化的字符串或数组
	 * @param  string       $action   要将为数组元素值类型，可取值: string(默认)|int
	 * @return array                  返回格式化后的数组
	 * @author martinzhang
	 */
	public static function fmtArray2StringOrInteger($var, $action='string'){
		$var = self::fmtArrayFilter($var);
		$returnArr = [];
		if(empty($var)){return [];}
		if($action=='str' || $action=='string'){
			foreach($var as $val){
				$returnArr[] = (string)$val;
			}
		}elseif($action=='int' || $action=='integer'){
			foreach($var as $val){
				$returnArr[] = (integer)$val;
			}
		}else{
			$returnArr = $var;
		}
		
		return $returnArr;
	}
	
	/**
	 * 将$where条件元素值类型格式化为mongodb乐见的字符型
	 * @param  array $where 数组格式的where条件
	 * @return array 返回新$where
	 * @author martinzhang
	 */
	public static function fmtMongoWhere2String($where){
		foreach($where as &$v){
			$v = (string)$v;
		}		
		return $where;
	}
	
	/**
	 * 格式化与solr相关的时间格式
	 * @param unknown $time
	 * @return mixed
	 */
	public static function fmtSolrTime($time){
		if(strpos($time,'T') > 0){
			return str_replace('Z', '', str_replace('T', ' ', $time));
		}else{
			return str_replace(' ', 'T', $time).'Z';
		}
	}
	
	/**
	 * 将普通数组查询简单格式化为Solr查询语法 - 用普通AND连接
	 * @param  arrayy $where  必选  待格式化的数组查询格式
	 * @return string             返回格式化后的字符
	 * @author martinzhang
	 */
	public static function fmtSolrQuery4AND($where){
		if(empty($where)){
			return '*:*';
		}
		$tmpQuey='';
		foreach($where as $key=>$value){
			if(trim($value)==''){continue 1;}
			if(is_integer($value)){
				$tmpQuey .= " $key:$value AND";
			}else{
				$tmpQuey .= " $key:\"$value\" AND";
			}				
		}
		return trim($tmpQuey, 'AND');
	}
	
	/**
	 * 将普通数组查询简单格式化为Solr查询语法 - 用普通OR连接(适用于多ids的in条件)
	 * @param  arrayy $arrIds  必选  待格式化的数组或字符串查询格式ids
	 * @param  string $idName  必选  需要查询的字段名
	 * @return string              返回格式化后的字符
	 * @author martinzhang
	 */
	public static function fmtSolrQuery4OR($arrIds, $idName){
		if(empty($where)){
			return '*:*';
		}
		$tmpQuey='';
		foreach($where as $key=>$value){
			if(trim($value)==''){continue 1;}
			if(is_integer($value)){
				$tmpQuey .= " $key:$value OR";
			}else{
				$tmpQuey .= " $key:\"$value\" OR";
			}				
		}
		return trim($tmpQuey, 'OR');
	}
	
	/**
	 * 将普通数组查询简单格式化为Solr查询语法 - 用普通OR连接(适用于多ids的in条件)
	 * @param  arrayy $arrIds  必选  待格式化的数组或字符串查询格式ids
	 * @param  string $idName  必选  需要查询的字段名
	 * @return string              返回格式化后的字符
	 * @author martinzhang
	 */
	public static function fmtSolrQuery4IN($arrIds, $idName){
		$arrIds = self::fmtArrayFilter($arrIds);
		$solrQuery = '';
		foreach($arrIds as $id){
			$solrQuery .= " $idName:$id OR";
		}
		return trim($solrQuery,'OR');
	}
	
	/**
	 * 格式化标准时间为短时间样式
	 * @param  max $time   待格式化的时间(可以是10位整数的时间戳，也可以是形如 YYYY-mm-dd hh:ii::ss 之类的标准格式时间)
	 * @param  int $revise 可选 时间修正值(当两服务器时间不步时)，正负值均可: +时间(后推时间)；-时间(前移时间)；单位：秒
	 * @return string      返回自定义格式时间
	 * @author martinzhang
	 */
	public static function fmtTime2Short($time, $revise=0){
		if($time==''){return false;}
		if($revise == '' || !is_numeric($revise)){
			$revise = 0;
		}
		if(!is_numeric($time)){
			$unixtime = strtotime($time) + $revise;
		}else{
			$unixtime = $time + $revise;
		}
		$today0time     = strtotime(date('Y-m-d 00:00:00')); //今天0点时间戳
		$yesterday0time = $today0time-86400;                 //昨天0点时间戳
		$blank = time() - $unixtime;						 //“帖子时间” 与 “当前时间差”(单位：秒)
		$blank = max($blank,1);
		switch($blank){
			case $blank < 60:
				$format=floor($blank/pow(60,0)).'秒前';
				break;
			case $blank < 60*60*1:
				$format=floor($blank/pow(60,1)).'分钟前';
				break;
			case $blank < 60*60*1 && $unixtime >= $today0time:
				$format=floor($blank/pow(60,2)).'小时前';
				break;
			case $blank >= 60*60*1 && $unixtime >= $today0time:
				$format='今天 '.date('H:i',$unixtime);
				break;
			case $unixtime >= $yesterday0time && $unixtime < $today0time:
				$format='昨天 '.date('H:i',$unixtime);
				break;
			case $blank < time()-mktime(0,0,0,1,1,date('Y')):
				$format=date('n月j日 H:i',$unixtime);
				break;
	
			default:
				$format=date('Y-m-d H:i',$unixtime);
		}
		return $format;
	}
	
	/**
	 * 将视频播放长度秒数格式化显示为 分'秒“ 格式
	 * @param  int $length 秒数
	 * @return array 格式化后的时间单位
	 */
	public static function fmtVideoLength($length){
		if($length==''){
			$length = 0;
		}
		$min = floor($length / 60);
		$sec = $length % 60;
		return ['min'=>$min, 'sec'=>$sec, 'lenstr'=>"{$min}'{$sec}\""];
	}
	
	/**
	 * 将手机号中间4位用星号替换
	 * @param int $mobile 手机号
	 * @return string 返回替换后的手机号
	 */
	public static function fmtMobile2Star($mobile){
		return substr_replace($mobile, '****', 3, 4);
	}
	
	/**
	 * 判断给定字符串是否为手机号码
	 * @param string $phoneNumber 待判断的字符串
	 * @return bool 是手机号码返回true; 不是手机号码返回false;
	 * @author martinzhang
	 */
	public static function isMobile($phoneNumber){
		if(!is_numeric($phoneNumber) || strlen($phoneNumber)!=11){
			return false;
		}
		if(preg_match('/^1[34578]\d{9}$/', $phoneNumber)){
			return true;
		}else{
			return false;
		}		
	}
	
	/**
	 * 判断给定字符串是否为邮箱地址
	 * @param string $email 待判断的字符串
	 * @return bool 是邮箱地址返回true; 不是邮箱地址返回false;
	 * @author martinzhang
	 */
	public static function isEmail($email){
		if(strpos($email, '@') < 1){
			return false;
		}
		if(preg_match('/^\w+([-.]+\w+)?@\w+([-.]+\w+)?\.\w+(\.\w+)?/', $email)){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * 判断给定字符串是否为日期(1970-1-1)
	 * @param string $date 待判断的字符串
	 * @return bool 是日期返回true; 不是日期返回false;
	 * @author martinzhang
	 */
	public static function isDate($date){
		if(preg_match('/^\d{4}[-](0?[0-9]|1[012])[-](0?[0-9]|[12][0-9]|3[01])$/', $date)){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * 判断给定字符串是否为时间(1970-1-1 12:30:33 或1970-1-1 12:30)
	 * @param string $time 待判断的字符串
	 * @return bool 是时间返回true; 不是时间返回false;
	 * @author martinzhang
	 */
	public static function isTime($time){
		if(preg_match('/^\d{4}[-](0?[0-9]|1[012])[-](0?[0-9]|[12][0-9]|3[01])\s+(0?[0-9]|[1][0-9]|2[0-3]):(0?[0-9]|[1-5][0-9])(:(0?[0-9]|[1-5][0-9]))?$/', $time)){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * 判断给定字符串是否含有中文字符
	 * @param string $str 待判断的字符串
	 * @return bool 含中文字符返回true; 不含中文字符返回false;
	 * @author martinzhang
	 */
	public static function isCN($str){
		if(preg_match("/[\x{4e00}-\x{9fa5}]/u", $str)){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * 以get方式请求远程资源
	 * @param string $url   待请求的远程资源
	 * @param array $params 参数
	 * @param int $timeout  设置最大超时时间(单位:秒)
	 * @return mixed
	 * @author martinzhang
	 */
	public static function curlGet($url, $params, $timeout=10){
		if(empty($url)){
			return self::responseError('url地址不能为空');
		}
		if(!is_array($params)){
			return self::responseError('params必须为数组类型');
		}
		if(!empty($params)){
			//下面将关联数组参数转换为以&符连接的URI参数
			$param2String = urldecode(http_build_query($params));
			if(strpos($url, '?') > 0){
				$url = rtrim($url,'&').'&'.$param2String;
			}else{
				$url = rtrim($url,'&').'?'.$param2String;
			}
		}
		
		//HTTP请求头信息
		$httpHeader[]='Content-Type: application/json;charset=utf-8';
		$httpHeader[]='User-Agent: Apache/2.4.6 (Unix)';
		
		//模拟用户使用的浏览器
		$useragent = 'Mozilla/5.0 (Windows NT 6.1; rv:22.0) Gecko/20100101 Firefox/22.0';
		
		$ch=curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);				//设置需要获取的URL地址，也可以在curl_init()函数中设置
		curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeader);	//设置HTTP头信息
		curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);		//设置最大延时时间，单位：秒
		curl_setopt($ch, CURLOPT_USERAGENT, $useragent);	//模拟用户使用的浏览器
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 	//使用自动跳转
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);	//跳过证书检查
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 	//设置将curl_exec()获取的信息以文件流的形式返回，而不是直接输出。true返回(不输出)；false不返回(直接输出)
		$data       = curl_exec($ch);						//执行
		$getInfo    = curl_getinfo($ch);					//获取一个cURL连接资源句柄的信息
		$curl_errno = curl_errno($ch);						//错误号
		curl_close($ch);									//关闭
		return ['statusCode'=>$getInfo['http_code'], 'message'=>$getInfo, 'content'=>$data];
	}	
	
	/**
	 * 以post方式请求远程资源
	 * @param string $url   待请求的远程资源
	 * @param array|string $params 参数
	 * @param int $timeout  设置最大超时时间(单位:秒)
	 * @return mixed
	 * @author martinzhang
	 */
	public static function curlPost($url, $params, $timeout=10){
		if(empty($url)){
			return self::responseError('url地址不能为空');
		}
		if(!is_array($params)){
			return self::responseError('params必须为数组类型');
		}
		
		//HTTP请求头信息
		if(is_array($params)){
			$httpHeader = [];
		}else{
			$httpHeader = [
					'Accept: application/json, text/xml, text/javascript, */*',
					'Content-Type: application/x-www-form-urlencoded',
			];
		}
		
		//模拟用户使用的浏览器
		$useragent = 'Mozilla/5.0 (Windows NT 6.1; rv:22.0) Gecko/20100101 Firefox/22.0';
		
		$ch=curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);				//设置需要获取的URL地址，也可以在curl_init()函数中设置
		curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeader);	//设置HTTP头信息
		curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);		//设置最大延时时间，单位：秒
		curl_setopt($ch, CURLOPT_USERAGENT, $useragent);	//模拟用户使用的浏览器
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 	//使用自动跳转
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);	//跳过证书检查		
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 	//设置将curl_exec()获取的信息以文件流的形式返回，而不是直接输出。true返回(不输出)；false不返回(直接输出)		
		curl_setopt($ch, CURLOPT_POST, true);				//设置启用时会发送一个常规的POST请求
		curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));		//设置POST参数
		$data       = curl_exec($ch);						//执行
		$getInfo    = curl_getinfo($ch);					//获取一个cURL连接资源句柄的信息
		$curl_errno = curl_errno($ch);						//错误号
		curl_close($ch);									//关闭
		return ['statusCode'=>$getInfo['http_code'], 'message'=>$getInfo, 'content'=>$data];
	}	
	
	/**
	 * 分页计算
	 * @param  total       总条数
	 * @param  pageSize    每页显示条数
	 * @param  pageCurrent 当前第几页(默认第1页)
	 * @param  blocks      水平摆放分页方块个数(默认10个)
	 * @return array       成功返回二维数组
	 * @author martinzhang
	 */
	public static function divPage($total, $pageSize, $pageCurrent, $blocks=10){
		if(!is_numeric($total)){return false;}
		if(!is_numeric($pageSize)){return false;}
		if(!is_numeric($pageCurrent)){$pageCurrent=1;}
		if(!is_numeric($blocks)){$blocks=5;}
		$pageTotal     = max(1,ceil($total/$pageSize)); 	//总页数
		$pageCurrent   = max($pageCurrent,1);
		$pageCurrent   = min($pageCurrent,$pageTotal);
		$groupTotal	   = ceil($pageTotal/$blocks);			//总组数
		$offset        = ($pageCurrent-1)*$pageSize;      	//起始条
		$length        = min($pageSize,$total-$offset);  	//当前页应查询显示条数 给limit $offset,$length用
		$end           = min($offset+$pageSize,$total);   	//结束条 给 for($i=$offset; $i<$end; $i++){...} 用
		$prePage       = max(1,$pageCurrent-1);           	//上一页(页码值)
		$nextPage      = min($pageTotal,$pageCurrent+1);  	//下一页(页码值)
		$groupCurrent  = ceil($pageCurrent/$blocks);	  	//当前组(当前第几组)
		///////////////////////////////////////////////////////////////////////
		$block_start   = ceil($pageCurrent/$blocks)*$blocks-$blocks+1;	//起始块
		$block_end     = ceil($pageCurrent/$blocks)*$blocks;			//结束块
		for($i=$block_start;$i<=min($block_end,$pageTotal);$i++){
			//水平摆放单元分布按钮方块
			$pageblocks[] = $i;
		}
		$lefBtnShow    = '';
		$rightBtnShow  = '';
		$blockBtnLeft  = max($block_start-1,1);			//水平摆放分页单元按钮 左翻页导航按钮
		$blockBtnRight = min($block_end+1,$pageTotal);	//水平摆放分页单元按钮 右翻页导航按钮
		if($groupCurrent > 1){
			$lefBtnShow = '1';							//左翻页导航按钮是否应该显示：1应该显示；否则不应该显示
		}
		if($groupCurrent < $groupTotal){
			$rightBtnShow = '1';						//右翻页导航按钮是否应该显示：1应该显示；否则应该不显示
		}
		//////////////////////////////////////////////////////////////////////////////////////////////////
		//返回值详情
		return array(
			'total'			=> $total,			//总条数
			'pageSize'		=> $pageSize,		//每页显示条数
			'pageTotal'		=> $pageTotal,		//总页数
			'pageCurrent'	=> $pageCurrent,	//当前第几页
			'offset'		=> $offset,			//起始条(偏移量)
			'length'		=> $length,			//当前页应查询条数 给limit $offset,$length用
			'end'			=> $end,			//结束条  给for($i=$offset;$i<$end;$i++)用
			'groupTotal'    => $groupTotal,		//总组数
			'groupCurrent'  => $groupCurrent,	//当前组数(当前第几组)
			'prePage'		=> $prePage,		//上一页(页码值)
			'nextPage'		=> $nextPage,		//下一页(页码值)
			'blockBtnLeft'  => $blockBtnLeft,	//水平摆放分页单元按钮 左翻页导航按钮
			'blockBtnRight' => $blockBtnRight,	//水平摆放分页单元按钮 右翻页导航按钮
			'leftBtnShow'	=> $lefBtnShow,		//左翻页导航按钮是否应该显示：1应该显示；否则不应该显示
			'rightBtnShow'	=> $rightBtnShow,	//右翻页导航按钮是否应该显示：1应该显示；否则不应该显示
			'blocks'		=> $pageblocks 		//水平摆放分页方块列表
		);
	}	

	/**
	 * 按指定中文字数长度截取中英文混合字符串
	 * @param  string     待截取的字符串
	 * @param  cnNum      需要截取相当于cnNum个汉字个数的长度
	 * @param  start      可选 起始截取位置(默认0，即从开头开始截取)
	 * @param  ifEllipsis 可选 返回的字符串末尾是否需要 .. 点点连接：true是(默认)；false否；
	 * @param  charset    可选 字符编码：支持 utf8(默认) 和 gbk
	 * @return 返回截取后的字符串
	 * @author martinzhang
	 */
	public static function mbSubstrMixStr($string, $cnNum, $start=0, $ifEllipsis=true, $charset='utf8'){
	    $start      = $start == '' ?  0 : $start;
	    $ifEllipsis = $ifEllipsis==true ? true : false;
	    $charset    = $charset=='' ? 'utf8' : $charset;
	    $code2Len   = array('gbk'=>2, 'utf8'=>3);              	//编码对应每汉字长度(单位：字节)
	    $lenString  = strlen($string);                        	//字符串总长度(单位：字节) 注：原来用 mb_strlen($string)
	    $LenSplit   = $cnNum * $code2Len[strtolower($charset)]; //需求截取长度(单位：字节)
	    $spaceLen   = $cnNum * 2;                               //需求占位(注：每个英文字符为1个占位，每个汉字为2个占位)
	    if($lenString <= $LenSplit){
	        return $string;
	    }else{        
	        for($i=-1; $i<=$spaceLen; $i++){
	            $len = $cnNum + $i;                              //本轮需要截取字符个数
	            $str=mb_substr($string,$start,$len,$charset);
	            if(strtolower($charset)=='utf8'){
	                //如果是utf8编码
	                @preg_match_all("/([\x{4e00}-\x{9fa5}｛｝￥¨±·×÷ˇˉ‐—―‖‘’“”…ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ∈∏∑√∝∞∠∥∧∨∩∪∫∮∴∵∶∷∽≈≌≠≡≤≥≮≯⊙⊥⌒①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛❶❷❸❹❺❻❼❽❾❿、。〃々〈〉《》「」『』【】〔〕〖〗〝〞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩︰︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹉﹊﹋﹌﹍﹎﹏﹑﹔﹕﹖﹙﹚﹛﹜﹟﹠﹡﹢﹣﹤﹦﹨﹩﹪﹫！＂＇（）＋，－／：；＜＝＞？［］＿｀｜～￣§×ΘΨ‖‥…№℡←↑→↓↖↗↘↙√∮⊕⊙⊿╱╲▁▂▃▄▅▆▇█▏▔▕■□▲△▼▽◆◇○◎●◢◣◤◥☀☂☃★☆☉☋☍☎☏☑☒☜☞☠☪☭☽☾♀♂♝♞♪♭✁✈✌✍✎✐✔✖✘✙✚✪✲❀❂❈❉❤❦❧〄〠㈜㈱㉿㊙㊚㊛㊣㊤㊥㊦㊧㊨囍]){1}/u",$str,$arrCh);
	                $currentCNs = count($arrCh[0]);              //本轮截取到的中文字符个数
	            }else{
	                //如果是gbk编码
	                @preg_match_all("/([\x80-\xff｛｝￥¨±·×÷ˇˉ‐—―‖‘’“”…ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ∈∏∑√∝∞∠∥∧∨∩∪∫∮∴∵∶∷∽≈≌≠≡≤≥≮≯⊙⊥⌒①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛❶❷❸❹❺❻❼❽❾❿、。〃々〈〉《》「」『』【】〔〕〖〗〝〞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩︰︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹉﹊﹋﹌﹍﹎﹏﹑﹔﹕﹖﹙﹚﹛﹜﹟﹠﹡﹢﹣﹤﹦﹨﹩﹪﹫！＂＇（）＋，－／：；＜＝＞？［］＿｀｜～￣§×ΘΨ‖‥…№℡←↑→↓↖↗↘↙√∮⊕⊙⊿╱╲▁▂▃▄▅▆▇█▏▔▕■□▲△▼▽◆◇○◎●◢◣◤◥☀☂☃★☆☉☋☍☎☏☑☒☜☞☠☪☭☽☾♀♂♝♞♪♭✁✈✌✍✎✐✔✖✘✙✚✪✲❀❂❈❉❤❦❧〄〠㈜㈱㉿㊙㊚㊛㊣㊤㊥㊦㊧㊨囍]){1}/",$str,$arrCh);
	                $currentCNs = floor(count($arrCh[0])/2);     //本轮截取到的中文字符个数(注：gbk有别于utf8)
	            }            
	            $chrSpace = $len - $currentCNs;                  //本轮截取包含非中文字符个数(非中文字符占位数)
	            $currentSpaces = $currentCNs * 2 + $chrSpace;    //本轮截取后得到总占位数
	            $diffSpace = $spaceLen - $currentSpaces;         //仍缺少的占位数
	            if($ifEllipsis==true && $diffSpace<=3){
	                $dot4space = array(1=>'', 2=>'..', 3=>'...');
	                $str .= $dot4space[$diffSpace];              //连接 点点点
	                if($diffSpace<=3){break 1;}
	            }else{
	                if($diffSpace<=1){break 1;}
	            }
	        }
	        return $str;
	    }
	}	
	
	/**
	 * 密码加密存放规则
	 * @param  string $password  待加密的明文密码
	 * @return string 返回加密后的密文
	 * @author martinzhang
	 */
	public static function pwdEncryptRule($password){
		$password = trim($password);
		return md5(md5($password).'|'.sha1($password));
	}	
	
	/**
	 * 拼接图片URL
	 * @param  string $local 数据库中存储的文件相对路径或七牛图片key
	 * @return string        返回完整URL路径
	 */
	public static function padImgUrl($local){
		$local = trim($local);
		if(is_numeric($local)){
			return rtrim(\Yii::$app->params['qiniu']['bucket']['image']['bucketUrl'], '/').'/'.$local;
		}elseif(strtolower(substr($local,0,7))=='http://' || strtolower(substr($local,0,8))=='https://'){
			return $local;
		}else{
			return rtrim(\Yii::$app->params['imageServer'], '/').'/upload/'.$local;
		}		
	}

	/**
	 * 拼接七牛播放路径
	 * @param  string $key    七牛的key值
	 * @param  string $bucket 七牛空间名称, 可选值  source_video:源视频空间  trans_video:转码后的视频空间
	 * @return string         返回完整可播放URL路径
	 */
	public static function padQiniuVideoUrl($key, $bucket){
		$key = trim($key);
		if($key!=''){
			return rtrim(\Yii::$app->params['qiniu']['bucket'][$bucket]['bucketUrl'], '/').'/'.$key;
		}else{
			return '';
		}
	}	
	
	/**
	 * 去除七牛路径取出key
	 * */
	public static function ridQiniuUrl($key,$bucket){
		$key = trim($key);
		if($key!=''){
			return str_replace(\Yii::$app->params['qiniu']['bucket'][$bucket]['bucketUrl'], '', $key);
		}else{
			return '';
		}
	}	

	/**
	 * 获取七牛云上文件存储key
	 * @return int|空     成功返回key值；失败返回空；
	 * @author martinzhang
	 */
	public static function getQiniuKey(){
		try {
			$redis = Yii::$app->redis;
			return $redis->incr('qiniuKey');
		} catch (\Exception $e) {
			//echo $e->getMessage();
			return '';
		}
	}

	/**
	 * 拼接用户昵称
	 * @param string $nickname      用户昵称
	 * @param int    $user_base_id  用户id
	 * @return string               返回拼装的昵称
	 */
	public static function padNickname($nickname, $user_base_id){
		$nickname = trim($nickname);
		if($nickname==''){
			return 'User:'.$user_base_id;
		}else{
			return $nickname;
		}
	}
	
	/**
	 * 将字符标签转为数组
	 * @param string $strTags      字符串标签(用逗号分隔)
	 * @param int    $arrTagMaxNum 截取保留最大标签元素个数
	 * @param int    $tagLen       每个标签最大保留字数
	 * @return array 返回转换后的数组标签
	 */
	public static function convStrTags2Arr($strTags, $arrTagMaxNum=10, $tagLen=10){
		$arrTags      = explode(',', $strTags);
		$arrTagMaxNum = min($arrTagMaxNum, count($arrTags));
		$resTagBox = [];
		for($i=0; $i<$arrTagMaxNum; $i++){
			$resTagBox[] = self::mbSubstrMixStr($arrTags[$i], $tagLen);
		}
		return $resTagBox;
	}
	
	/**
	 * 设置站内用户Token
	 * @param  integer $user_base_id 用户id
	 * @return string|bool           成功返回token值；失败返回false；
	 * @author martinzhang
	 */
	public static function setToken($user_base_id){
		//生成token
		$token = sha1(time().$user_base_id);
	
		//放入redis
		try {
			$redis = Yii::$app->redis;
			$res   = $redis->hset("userToken:$user_base_id", 'token', $token);
			if($res===false){
				return false;
			}else{
				return $token;
			}
				
		} catch (\Exception $e) {
			//echo $e->getMessage();
			return false;
		}
	}
	
	/**
	 * 获取站内用户Token
	 * @param  integer $user_base_id 用户id
	 * @return string|null           成功返回token值或null；失败返回false；
	 * @author martinzhang
	 */
	public static function getToken($user_base_id){
		try {
			$redis = Yii::$app->redis;
			return $redis->hget("userToken:$user_base_id", 'token');
		} catch (\Exception $e) {
			//echo $e->getMessage();
			return false;
		}
	}
	
	/**
	 * 删除资源
	 * @param string $path 待删除文件的相对路径
	 * @return bool  true|false
	 */
	public static function deleteFile($path){
		$path = trim($path);
		if(strtolower(substr($path,0,7))=='http://' || strtolower(substr($path,0,8))=='https://'){
			//远程文件，调用接口删除
			
		}else{
			//本地文件，直接删除
			if(file_exists(\Yii::$app->params['uploadPath'].$path)){
				return @unlink(\Yii::$app->params['uploadPath'].$path);
			}			
		}
	}
	
	/**
	 * 返回响应消息
	 * @return array
	 * @author martinzhang
	 */
	public static function response($arrResponse=array()){
		if(!is_array($arrResponse)){
			return ['status'=>1, 'msg'=>\Yii::$app->params['errlist'][1], 'data'=>[]];
		}
		if(isset($arrResponse['data']) && !is_array($arrResponse['data'])){
			return ['status'=>2, 'msg'=>\Yii::$app->params['errlist'][2], 'data'=>[]];
		}
		$result = ['status'=>0, 'msg'=>'ok', 'data'=>[]];
		 
		//合并数组，若包含相同的键，那么最末一个值将覆盖前面的值
		return array_merge($result, $arrResponse);
	}	
	
	/**
	 * 返回“成功”消息
	 * @param array $data 待返回的数据
	 * @return array
	 * @author martinzhang
	 */
	public static function responseOK($data){
		if(empty($data)){
			$data = [];
		}
		if(!is_array($data)){
			return ['status'=>2, 'msg'=>\Yii::$app->params['errlist'][2], 'data'=>[]];
		}
		return self::response(['data'=>$data]);
	}	
	
	/**
	 * 返回“失败”消息
	 * @param string $errmsg 待返回失败消息内容
	 * @return array
	 * @author martinzhang
	 */
	public static function responseError($errmsg='操作失败'){
		return self::response(['status'=>6, 'msg'=>'[内部错误]'.$errmsg]);
	}
	
	/**
	 * 返回“指定错误号”消息
	 * @param string $errcode 待返回预定义错误号
	 * @param array  $data    待返回的数据
	 * @return array
	 * @author martinzhang
	 */
	public static function responseErrCode($errcode, $data=[]){
		return self::response(['status'=>$errcode, 'msg'=>\Yii::$app->params['errlist'][$errcode], 'data'=>$data]);		
	}
	
	/**
	 * 返回“用户自定义错误号”消息
	 * @param int    $errcode 待返回预定义错误号
	 * @param string $errmsg  待返回的消息内容
	 * @param array  $data    待返回的数据
	 * @return array
	 * @author martinzhang
	 */
	public static function responseUErr($errcode, $errmsg, $data=[]){
		if($errcode < 51){
			return ['status'=>4, 'msg'=>\Yii::$app->params['errlist'][4], 'data'=>[]];
		}
		return self::response(['status'=>$errcode, 'msg'=>$errmsg, 'data'=>$data]);		
	}
	
	
}
